package cn;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.Verification;
import java.security.NoSuchAlgorithmException;
import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;


public class JwtTool {

    public static final String JWT_SECRET = "LIUSIQING";
    public static final Algorithm ALGORITHM = algorithm();

    /**
     * 签名算法，根据密钥，生成Algorithm实例，通常应用生命周期内都可以使用这个对象
     *
     * @return
     */
    private static final Algorithm algorithm() {
        final Map<String, String> keys = RSAUtils.createKeys(1024);
        Algorithm algorithm = null;
        try {
            algorithm = Algorithm.RSA512(RSAUtils.getPublicKey(keys.get("publicKey")), RSAUtils.getPrivateKey(keys.get("privateKey")));
        } catch (NoSuchAlgorithmException noSuchAlgorithmException) {
            noSuchAlgorithmException.printStackTrace();
        } catch (InvalidKeySpecException invalidKeySpecException) {
            invalidKeySpecException.printStackTrace();
        }
        return algorithm;
    }

    /**
     * 用于生成token的对象
     *
     * @return
     */
    private static final JWTCreator.Builder builder() {
        return JWT.create();
    }

    /**
     * 生成token
     *
     * @param payload 载体
     * @param time    有效时长
     * @return token
     */
    public static final String token(Map<String, String> payload, long time) {
        final JWTCreator.Builder builder = builder();
        //配置token的Header自定义部分
        Map<String, Object> headers = new HashMap<String, Object>(2);
        headers.put("alg", "RSA");
        headers.put("typ", "JWT");
        builder.withHeader(headers);
        //配置token的PayLoad部分预定义字段,不强制使用
        //配置PayLoad部分自定义字段
        for (Map.Entry<String, String> entry : payload.entrySet()) {
            builder.withClaim(entry.getKey(), entry.getValue());
        }
        builder.withIssuedAt(new Date());
        //生效时间,当前时间加上有效时间
        builder.withExpiresAt(new Date(System.currentTimeMillis() + time));
        //根据algorithm，签名后生成token
        String token = builder.sign(ALGORITHM);
        return token;
    }

    /**
     * 解密token
     *
     * @param token
     * @return
     */
    public static final Map<String, String> decode1(String token) {
        //解密token
        DecodedJWT decodedJWT = JWT.decode(token);
        final String header = decodeBase64Url(decodedJWT.getHeader());
        final String payload = decodeBase64Url(decodedJWT.getPayload());
        final String signature = decodedJWT.getSignature();
        final String jwtToken = decodedJWT.getToken();
        Map<String, String> jwt = new HashMap<String, String>(4);
        jwt.put("header", header);
        jwt.put("payload", payload);
        jwt.put("signature", signature);
        jwt.put("jwtToken", jwtToken);
        System.out.println(payload);
        return jwt;
    }

    public static final DecodedJWT decode2(String token){
        return JWT.decode(token);
    }

    public static final boolean verify(Map<String,Object> payload,String token) {
        payload.put("exp",200);
        try{
            Verification verification = JWT.require(ALGORITHM);
            for (Map.Entry<String,Object> entry : payload.entrySet()) {
                String key = entry.getKey();
                if ("iss".equals(key) || "sub".equals(key) || "aud".equals(key) || "exp".equals(key) || "nbf".equals(key) ||
                        "iat".equals(key) || "jti".equals(key) || "user-definde1".equals(key) || "user-definde2".equals(key)){
                    continue;
                }
                verification.withClaim(entry.getKey(),entry.getValue().toString());
            }
            System.out.println(new GsonTool<String,Object>().mapToJson(payload));
            verification.acceptExpiresAt(System.currentTimeMillis()+200);
            verification.acceptIssuedAt(200);
            final JWTVerifier jwtVerifier = verification.build();
            final DecodedJWT verify = jwtVerifier.verify(token);
        }catch (Exception e){
            e.printStackTrace();
            return false;
        }
        return true;
    }


    public static void main(String[] args) throws Exception {
        final HashMap<String, String> stringStringHashMap = new HashMap<String, String>(1);
        stringStringHashMap.put("hello", "11");
        final String token = token(stringStringHashMap, 5000);
        final String payload = decode1(token).get("payload");
        final Map<String, Object> map = new GsonTool<String, Object>().jsonToMap(payload, String.class, Object.class);
        verify(map,token);
    }

    private static String decodeBase64Url(String base64Url) {
        return new String(Base64.getUrlDecoder().decode(base64Url));
    }


}
